﻿using System;
using System.Collections.Generic;
using UniFrame.Scene;
using UnityEngine;
using UnityEngine.UIElements;

namespace UniFrame.UI
{
    /// <summary>
    /// UI管理器
    /// </summary>
    public class UIManager
    {
        private Dictionary<UniRes, PanelElem> uiDict;
        private Stack<BasePanel> panelStack;
        /// <summary>
        /// 默认画布名字
        /// </summary>
        public const string defaultCanvasName = "Canvas";
        /// <summary>
        /// 当前画布
        /// </summary>
        public GameObject currentCanvas { get; private set; }
        /// <summary>
        /// UI管理器所在的场景
        /// </summary>
        public BaseScene baseScene { get; private set; }

        /// <summary>
        /// 实例化一个UI管理器
        /// </summary>
        /// <param name="canvas">指定一个画布对象,不存在则查找默认画布</param>
        public UIManager(GameObject canvas = null,BaseScene scene = null)
        {
            currentCanvas = canvas ?? GameObject.Find(defaultCanvasName);
            if (currentCanvas == null)
                throw new NullReferenceException();
            baseScene = scene;
            uiDict = new Dictionary<UniRes, PanelElem>();
            panelStack = new Stack<BasePanel>();
        }
        /// <summary>
        /// 推入一个面板
        /// </summary>
        /// <param name="basePanel"></param>
        public void Push(BasePanel basePanel)
        {
            if (basePanel == null)
                throw new NullReferenceException();
            PanelElem panelElem;
            if(!uiDict.TryGetValue(basePanel.uniRes,out panelElem))
                panelElem = GetSingleUI(basePanel.uniRes, basePanel);
            if (panelStack.Count != 0)
                panelStack.Peek().OnPause();
            panelStack.Push(panelElem.basePanel);
            if(panelElem.basePanel.IsFirstLoad)
            {
                panelElem.basePanel.AttachGameObject(this);
                panelElem.basePanel.Initialize();
                panelElem.basePanel.IsFirstLoad = false;
            }
            panelElem.basePanel.OnEnter();
        }
        /// <summary>
        /// 弹出一个面板
        /// </summary>
        public bool Pop()
        {
            if (panelStack.Count == 0)
                return false;
            if (panelStack.Count != 0)
                panelStack.Pop().OnExit();
            if (panelStack.Count != 0)
                panelStack.Peek().OnResume();
            return true;
        }
        /// <summary>
        /// 当前栈中面板个数
        /// </summary>
        public int PanelCount { get { return panelStack.Count; } }
        /// <summary>
        /// 获取并缓存一个面板元素
        /// </summary>
        /// <param name="uniRes"></param>
        /// <param name="basePanel"></param>
        /// <returns></returns>
        internal PanelElem GetSingleUI(UniRes uniRes,BasePanel basePanel)
        {
            PanelElem panelElem;
            if (!uiDict.TryGetValue(uniRes, out panelElem))
            {
                GameObject go = GameObject.Instantiate(Resources.Load<GameObject>(uniRes.Path));
                go.transform.SetParent(currentCanvas.transform, false);
                panelElem = new PanelElem(go, basePanel);
                uiDict.Add(uniRes, panelElem);
            }
            return panelElem;
        }
        /// <summary>
        /// 销毁一个面板元素
        /// </summary>
        /// <param name="uniRes"></param>
        internal void DestroySingleUI(UniRes uniRes)
        {
            if (uiDict.ContainsKey(uniRes))
            {
                if (panelStack.Contains(uiDict[uniRes].basePanel))
                {
                    while (panelStack.Peek() != uiDict[uniRes].basePanel)
                        Pop();
                    Pop();
                }
                GameObject.Destroy(uiDict[uniRes].gameObject);
                uiDict.Remove(uniRes);
            }
        }
        /// <summary>
        /// 销毁所有面板
        /// </summary>
        public void DestroyAll()
        {
            while (Pop()) ;
            foreach (var item in uiDict)
                GameObject.Destroy(item.Value.gameObject);
            uiDict.Clear();
        }
        /// <summary>
        /// 获取一个已存在面板
        /// </summary>
        /// <returns></returns>
        public BasePanel RetrievePanel(string path)
        {
            BasePanel basePanel = null;
            foreach (var item in uiDict)
                if (item.Key.Path == path)
                    basePanel = item.Value.basePanel;
            return basePanel;
        }
    }
}
